package com.sky.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.PasswordConstant;
import com.sky.constant.StatusConstant;
import com.sky.context.BaseContext;
import com.sky.dto.EmployeeDTO;
import com.sky.dto.EmployeeLoginDTO;
import com.sky.dto.EmployeePageQueryDTO;
import com.sky.entity.Category;
import com.sky.entity.Employee;
import com.sky.exception.AccountLockedException;
import com.sky.exception.AccountNotFoundException;
import com.sky.exception.PasswordErrorException;
import com.sky.mapper.EmployeeMapper;
import com.sky.result.PageResult;
import com.sky.service.EmployeeService;
import org.springframework.beans.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class EmployeeServiceImpl implements EmployeeService {

    // 密码错误标记的Key
    private static final String LOGIN_PASSWORD_ERROR_KEY = "login:error:";
    // 账号被锁定的key
    private static final String LOGIN_LOCK_ERROR_KEY = "login:lock:";

    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * 员工登录
     *
     * @param employeeLoginDTO
     * @return
     */
    public Employee login(EmployeeLoginDTO employeeLoginDTO) {
        String username = employeeLoginDTO.getUsername();
        String password = employeeLoginDTO.getPassword();

        // 检验员工账号是否被锁定
        validateAccountLock(username);

        //1、根据用户名查询数据库中的数据
        Employee employee = employeeMapper.getByUsername(username);

        //2、处理各种异常情况（用户名不存在、密码不对、账号被锁定）
        if (employee == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对
        // TODO 后期需要进行md5加密，然后再进行比对
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        // 密码错误
        if (!password.equals(employee.getPassword())) {

            log.info("密码比对错误");

            // 记录员工的密码错误标记，并设置有效期为5分钟
            redisTemplate.opsForValue().set(getKey(username)
                    , "-", 5, TimeUnit.MINUTES);
            // 获取该员工的密码错误标记，如果标记的数量大于等于5，设置账号锁定
            Set<Object> keys = redisTemplate.keys(LOGIN_PASSWORD_ERROR_KEY + username + ":*");
            if (keys != null && keys.size() >= 5) {
                log.info("用户5分钟之内，错误次数超过5次，锁定账号一小时");
                redisTemplate.opsForValue().set(LOGIN_LOCK_ERROR_KEY + username, ":", 1, TimeUnit.HOURS);
                throw new AccountLockedException(MessageConstant.LOGIN_LOCK_ERROR);
            }


            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        if (employee.getStatus() == StatusConstant.DISABLE) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }

        //3、返回实体对象
        return employee;
    }


    // 检验员工账号是否被锁定
    private void validateAccountLock(String username) {
        Object flag = redisTemplate.opsForValue().get(LOGIN_LOCK_ERROR_KEY + username);
        if (ObjectUtils.isNotEmpty(flag)){
            log.info("账号被锁定，限制登录");
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }
    }


    // 拼接 redis的key
    private String getKey(String username) {
        return LOGIN_PASSWORD_ERROR_KEY + username + ":" + RandomStringUtils.randomAlphabetic(5);
    }

    @Override
    public void save(EmployeeDTO employeeDTO) {
        // 1.补全实体属性
        Employee employee = new Employee();

        //对象属性拷贝
        BeanUtils.copyProperties(employeeDTO, employee);

        // 设置密码-加密
        employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
        // 设置默认状态
        employee.setStatus(StatusConstant.ENABLE);

//        employee.setCreateTime(LocalDateTime.now());
//        employee.setUpdateTime(LocalDateTime.now());

//        employee.setCreateUser(BaseContext.getCurrentId()); // 当前登录员工ID
//        employee.setUpdateUser(BaseContext.getCurrentId()); // 当前登录员工ID


        // 2.调用mapper，保存数据
        employeeMapper.insert(employee);

    }


    @Override
    public PageResult page(EmployeePageQueryDTO employeePageQueryDTO) {
        // 1.设置分页参数
        PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());

        // 2.执行查询
        List<Employee> employeeList = employeeMapper.list(employeePageQueryDTO.getName());


        // 3.解析并封装结果
        Page<Employee> page = (Page<Employee>) employeeList;

        return new PageResult(page.getTotal(),page.getResult());
    }

    @Override
    public void enableOrDisable(Integer status, Long id) {
        Employee employee = Employee.builder()
                .id(id)
                .status(status)
//                .updateTime(LocalDateTime.now())
//                .updateUser(BaseContext.getCurrentId())
                .build();

        employeeMapper.update(employee);
    }

    /**
     * 修改回显
     * @param id
     */
    @Override
    public Employee selectById(Long id) {

        Employee employee = employeeMapper.selectById(id);
        employee.setPassword("****");
        return employee;

    }

    @Override
    public void update(EmployeeDTO employeeDTO) {
//        Employee emp = Employee.builder()
//                .id(employeeDTO.getId())
//                .idNumber(employeeDTO.getIdNumber())
//                .name(employeeDTO.getName())
//                .phone(employeeDTO.getPhone())
//                .sex(employeeDTO.getSex())
//                .username(employeeDTO.getUsername())
//                .updateTime(LocalDateTime.now())
//                .updateUser(BaseContext.getCurrentId())
//                .build();

        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeDTO, employee);

        //employee.setUpdateTime(LocalDateTime.now());
        //employee.setUpdateUser(BaseContext.getCurrentId());

        employeeMapper.update(employee);

    }
}
